//: Playground - noun: a place where people can play

import Cocoa

var str = "Hello, playground"

class Door {
    var opened : Bool = false
    var locked : Bool = false
    let width : Int = 32
    let height : Int = 72
    let weight : Int = 10
    let color : String = "Red"

    func open() -> String {
        opened = true
        return "C-r-r-e-e-a-k-k... the door is open!"
    }
    
    func close() -> String {
        opened = false
        return "C-r-r-e-e-a-k-k... the door is closed!"
    }
    
    func lock() -> String {
        locked = true
        return "C-l-i-c-c-c-k-k... the door is locked!"
    }
    
    func unlock() -> String {
        locked = false
        return "C-l-i-c-c-c-k-k... the door is unlocked!"
    }
}

let frontDoor = Door()

frontDoor.open()
frontDoor.close()

frontDoor.lock()
frontDoor.unlock()

class NewDoor {
    var opened : Bool = false
    var locked : Bool =  false
    let width : Int
    let height : Int
    let weight : Int
    var color : String
    
    init(width : Int = 32, height : Int = 72, weight : Int = 10, color : String = "Red") {
        self.width = width;
        self.height = height
        self.weight = weight
        self.color = color
    }
    
    func open() -> String {
        if opened == false {
            opened = true
            return "C-r-r-e-e-a-k-k... the door is open!"
        }
        else {
            return "The door is already open!"
        }
    }
    
    func close() -> String {
        if opened == true {
            opened = false
            return "C-r-r-e-e-a-k-k... the door is closed!"
        }
        else {
            return "The door is already closed!"
        }
    }
    
    func lock() -> String {
        if opened == false {
            locked = true
            return "C-l-i-c-c-c-k-k... the door is locked!"
        }
        else {
            return "You cannot lock an open door!"
        }
    }
    
    func unlock() -> String {
        if opened == false {
            locked = false
            return "C-l-i-c-c-c-k-k... the door is unlocked!"
        }
        else {
            return "You cannot unlock an open door!"
        }
    }
}

let newFrontDoor = NewDoor()

newFrontDoor.close()
newFrontDoor.open()

newFrontDoor.lock()
newFrontDoor.unlock()

newFrontDoor.locked
newFrontDoor.opened

newFrontDoor.width
newFrontDoor.height
newFrontDoor.weight

let newBackDoor = NewDoor(width: 36, height: 80, weight: 20, color: "Green")
newBackDoor.color = "White"

class Portal {
    var opened : Bool = false;
    var locked : Bool = false;
    let width : Int
    let height : Int
    let weight : Int
    let name : String
    var color : String
    
    init(name : String, width : Int = 32, height : Int = 32, weight : Int = 10, color : String = "Red") {
        self.name = name
        self.width = width
        self.height = height
        self.weight = weight
        self.color = color
    }
    
    func open() -> String {
        if opened == false {
            opened = true
            return "C-r-r-e-e-a-k-k... the \(name) is open!"
        }
        else {
            return "The \(name) is already open!"
        }
    }
    
    func close() -> String {
        if opened == true {
            opened = false
            return "C-r-r-e-e-a-k-k... the \(name) is closed!"
        }
        else {
            return "The \(name) is already closed!"
        }
    }
    
    func lock() -> String {
        if opened == false {
            locked = true
            return "C-l-i-c-c-c-k-k... the \(name) is locked!"
        }
        else {
            return "You cannot lock an open \(name)!"
        }
    }
    
    func unlock() -> String {
        if opened == false {
            locked = false
            return "C-l-i-c-c-c-k-k... the \(name) is unlocked!"
        }
        else {
            return "You cannot unlock an open \(name)!"
        }
    }
}

class NiceDoor : Portal {
    init(width : Int = 32, height: Int = 72, weight: Int = 10, color: String = "Red") {
        super.init(name: "door", width: width, height: height, weight: weight, color: color)
    }
}

class NiceWindow : Portal {
    init(width : Int = 48, height: Int = 48, weight: Int = 5, color: String = "Blue") {
        super.init(name: "window", width: width, height: height, weight: weight, color: color)
    }
}

let sunRoomDoor = NiceDoor()

sunRoomDoor.close()
sunRoomDoor.open()

sunRoomDoor.lock()
sunRoomDoor.unlock()

sunRoomDoor.locked
sunRoomDoor.opened

sunRoomDoor.width
sunRoomDoor.height
sunRoomDoor.weight


let bayWindow = NiceWindow()

bayWindow.close()
bayWindow.open()

bayWindow.lock()
bayWindow.unlock()

bayWindow.locked
bayWindow.opened

bayWindow.width
bayWindow.height
bayWindow.weight

class CombinationDoor : NiceDoor {
    var combinationCode : String?
    
    override func lock() -> String {
        return "This method is not valid for a combination door!"
    }
    
    override func unlock() -> String {
        return "This method is not valid for a combination door!"
    }
    
    func lock(combinationCode : String) -> String {
        if opened == false {
            if locked == true {
                return "The \(name) is already locked!"
            }
            self.combinationCode = combinationCode
            locked = true
            return "C-l-i-c-c-c-k-k... the \(name) is locked!"
        }
        else {
            return "You cannot lock an open \(name)"
        }
    }
    
    func unlock(combinationCode : String) -> String {
        if opened == false {
            if locked == false {
                return "The \(name) is already unlocked!"
            }
            else {
                if self.combinationCode != combinationCode {
                    return "Wrong code... the \(name) is still locked!"
                }
            }
            locked = false
            return "C-l-i-c-c-c-k-k... the \(name) is unlocked!"
        }
        else {
            return "You cannot unlock an open \(name)"
        }
    }
}

let securityDoor = CombinationDoor()

// show values of the properties
securityDoor.width
securityDoor.height
securityDoor.weight
securityDoor.color
securityDoor.combinationCode

// unlock the door without providing a combination
securityDoor.unlock()

// lock the door without providing a combination
securityDoor.lock()

// unlock the door with a combination
securityDoor.unlock("6809")

// lock the door with a combination
securityDoor.lock("6809")

// unlock the door with the wrong combination
securityDoor.unlock("6502")

// unlock the door with the right combination
securityDoor.unlock("6809")

class Tractor {
    let horsePower : Int
    let color : String
    
    init(horsePower : Int, color : String) {
        self.horsePower = horsePower
        self.color = color
    }
    
    convenience init(horsePower : Int) {
        self.init(horsePower: horsePower, color: "Green")
    }
    
    convenience init() {
        self.init(horsePower: 42, color: "Green")
    }
}

let myBigTractor = Tractor()
let myBiggerTractor = Tractor(horsePower: 71)
let myYardTractor = Tractor(horsePower: 16, color: "Orange")

// enumerations
enum FuelType : String {
    case Gasoline = "89 octane"
    case Diesel = "sulpher free"
    case Biodiesel = "vegetable oil"
    case Electric = "30 amps"
    case NaturalGas = "coalbed methane"
}

var engine : FuelType = .Gasoline

var vehicleName : String

switch engine {
case .Gasoline:
    vehicleName = "Ford F-150"
    
case .Diesel:
    vehicleName = "Ford F-250"
    
case .Biodiesel:
    vehicleName = "Custom Van"
    
case .Electric:
    vehicleName = "Toyota Prius"
    
case .NaturalGas:
    vehicleName = "Utility Truck"
}

print("Vehicle \(vehicleName) takes \(engine.rawValue)")

enum TransmissionType {
    case Manual4Gear
    case Manual5Gear
    case Automatic
}

struct Vehicle {
    var fuel : FuelType
    var transmission : TransmissionType
}

var dieselAutomatic = Vehicle(fuel: .Diesel, transmission: .Automatic)
var gasoline4Speed = Vehicle(fuel: .Gasoline, transmission: .Manual4Gear)

// *****************************
// value type vs reference type
// *****************************

// In Swift, structures are value types
struct Structure {
    var copyVar : Int = 10
}

var struct1 = Structure() //struct1 created
var struct2 = struct1 // struct2 is a copy of struct1
struct2.copyVar = 20 // change struct2's copyVar
struct1.copyVar // struct1's copyVar
struct2.copyVar // struct2's copyVar

// In Swift, classes are reference types
class Class {
    var copyVar : Int = 10
}

var class1 = Class() // class1 instantiated
var class2 = class1 // class2 is a reference to class1
class2.copyVar = 20 // change class2's copyVar
class1.copyVar // class1's copyVar
class2.copyVar // class2's copyVar
